#pragma once

#include <WinSvc.h>
#include "Macro.h"

#include <string.h>

#include <string>
#include <vector>
#include <list>
#include <map>
using namespace std;
// Release algorithms (release policies)

template <typename T>
struct CCloseHandle
{
	void Close(T handle)
	{
// 		cout << "Handle is released" << endl;         // for testing
		::CloseHandle(handle);
	}

protected:
	~CCloseHandle()
	{
	}
};

template <typename T>
struct CCloseFindFileHandle
{
	void Close(T handle)
	{
		::FindClose( handle );
	}

protected:
	~CCloseFindFileHandle()
	{
	}
};

template <typename T>
struct CCloseSocketH
{
	void Close(T handle)
	{
		::closesocket( handle );
	}

protected:
	~CCloseSocketH()
	{
	}
};

template <typename T>
struct CCloseRegKey
{
	void Close(T handle)
	{
		::RegCloseKey(handle);
	}

protected:
	~CCloseRegKey()
	{
	}
};


template <typename T>
struct SCloseLibrary
{
	void Close(T handle)
	{
		::FreeLibrary(handle);
	}

protected:
	~SCloseLibrary()
	{
	}
};


template <typename T>
struct CCloseViewOfFile
{
	void Close(T handle)
	{
		::UnmapViewOfFile(handle);
	}

protected:
	~CCloseViewOfFile()
	{
	}
};

template <typename T>
struct CCloseServiceHandle
{
	void Close(T handle)
	{
		::CloseServiceHandle(handle);
	}

protected:
	~CCloseServiceHandle()
	{
	}
};


//////////////////////////////////////////////////////////////////////////
// Class CSmartHandle which implements release policy.
// Second template parameter is ReleaseAlgorithm which is template itself.

template <typename HandleType, template <typename> class ReleaseAlgorithm, HandleType NULL_VALUE = NULL>
class CSmartHandle : public ReleaseAlgorithm<HandleType>
{
public:
	CSmartHandle()
	{
		m_Handle = NULL_VALUE;
	}

	CSmartHandle(HandleType h)
	{
		m_Handle = h;
	}

	HandleType GetHandle()
	{
		return m_Handle;
	}

	HandleType operator=(HandleType h) 
	{
		if ( m_Handle != h )
		{
			CleanUp();
			m_Handle = h;
		}
		return(*this);  
	}

	operator HandleType()
	{
		return m_Handle;
	}

	HandleType* GetPointer()
	{
		return &m_Handle;
	}

	HandleType operator->()                 // for using as smart pointer
	{
		return m_Handle;
	}

	operator bool()
	{
		return IsValid();
	}

	bool IsValid()
	{
		return m_Handle != NULL_VALUE;
	}

	~CSmartHandle()
	{
		CleanUp();
	}

public:
	void CleanUp()
	{
		if ( m_Handle != NULL_VALUE )
		{
			Close( m_Handle );
			m_Handle = NULL_VALUE;
		}
	}

private:
	HandleType m_Handle;
};

// For using in the client code (definitions of standard Windows handles):
typedef CSmartHandle<HANDLE,    CCloseHandle>                         CAutoGeneralHandle;
typedef CSmartHandle<HKEY,      CCloseRegKey>                         CAutoRegKey;
typedef CSmartHandle<PVOID,     CCloseViewOfFile>                     CAutoViewOfFile;
typedef CSmartHandle<HMODULE,   SCloseLibrary>                        CAutoLibrary;
typedef CSmartHandle<HANDLE,    CCloseHandle, INVALID_HANDLE_VALUE>   CAutoFile;
typedef CSmartHandle<SC_HANDLE, CCloseServiceHandle>                  CAutoServiceHandle;
typedef CSmartHandle<HANDLE,    CCloseFindFileHandle, INVALID_HANDLE_VALUE>   CAutoFindFile;

typedef CSmartHandle<SOCKET,    CCloseSocketH, INVALID_SOCKET>        CAutoSocketH;

//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////


class CSemaphoreHandle
{
private:
	HANDLE    m_hSemaphoreWork;

public:
	CSemaphoreHandle()
	{
		m_hSemaphoreWork = ::CreateSemaphore( 0, 0, 0x7FFFFFFF, NULL );
	}
	~CSemaphoreHandle()
	{
		Close();
	}
	operator HANDLE()
	{
		return m_hSemaphoreWork;
	}
	void Close()
	{
		::CloseHandle( m_hSemaphoreWork );
		m_hSemaphoreWork = NULL;
	}
	void SignalObject()
	{
		::ReleaseSemaphore( m_hSemaphoreWork, 1, NULL );
	}
};


template <typename Job>
class CJobQueue
{
public:
	CJobQueue( );
	virtual ~CJobQueue( );

public:
	void    SubmitJob( const Job& x );
	long    GetJob( Job& cJob );
	Job     GetPtrJob( );
	BOOL    IsEmpty();
	BOOL    Is_Signaled( DWORD _dwMillisec = INFINITE );
	long    GetSize();

public:
	HANDLE  GetSignalObject();

private:
	list<Job>            m_cListJob;
	CResGuard            m_rgJob;
	CSemaphoreHandle     m_cSemaphoreHandle;
};

template <typename Job>
CJobQueue<Job>::CJobQueue( )
{}

template <typename Job>
CJobQueue<Job>::~CJobQueue( )
{}

template <typename Job>
BOOL CJobQueue<Job>::IsEmpty( )
{
	CRI_PROTECT( &m_rgJob );

	return m_cListJob.empty();
}
template <typename Job>
long CJobQueue<Job>::GetSize()
{
	CRI_PROTECT( &m_rgJob );
	return (long)m_cListJob.size();
}
template <typename Job>
HANDLE CJobQueue<Job>::GetSignalObject()
{
	return m_cSemaphoreHandle;
}
template <typename Job>
BOOL CJobQueue<Job>::Is_Signaled( DWORD _dwMillisec )
{
	return EQL( ::WaitForSingleObject( m_cSemaphoreHandle, _dwMillisec ), WAIT_OBJECT_0 );
}

template <typename Job>
void CJobQueue<Job>::SubmitJob( const Job& x )
{
	CRI_PROTECT( &m_rgJob );

	m_cListJob.push_back( x );
	m_cSemaphoreHandle.SignalObject();
}

template <typename Job>
long CJobQueue<Job>::GetJob( Job& cJob )
{
	CRI_PROTECT( &m_rgJob );

	if ( m_cListJob.empty( ) )
	{
		return ERROR_RET;
	}

	cJob = m_cListJob.front();
	m_cListJob.pop_front();
	return SUCCESS_RET;
}

template <typename Job>
Job CJobQueue<Job>::GetPtrJob()
{
	CRI_PROTECT( &m_rgJob );

	if ( m_cListJob.empty( ) )
	{
		return NULL;
	}

	Job cJob = m_cListJob.front();
	m_cListJob.pop_front();
	return cJob;
}
//////////////////////////////////////////////////////////////////////////


